package com.ecp.commons.interceptor;

import java.util.Collections;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;

import com.ecp.commons.cache.CacheService;
import com.ecp.commons.serialization.SerializableObject;

@Aspect
@Scope("prototype")
@Repository
public class CacheInterceptor {

	@Resource
	private CacheService			entityCache;

	private static Log				log			= LogFactory.getLog(CacheInterceptor.class);

	private static final boolean	LOGENABLE	= false;

	//@Around("execution(* com.ecp.commons.db.GenericDAO.*(..))")
	public Object doCache(ProceedingJoinPoint joinPoint) throws Throwable {
		long begin = System.currentTimeMillis();
		String operateType = joinPoint.getSignature().getName();
		Object[] args = joinPoint.getArgs();
		Object obj = null, cacheObj = null;
		Class<?> cls = null;

		if (operateType.equals("load") && args.length == 2) {
			cls = args[1].getClass();
			cacheObj = entityCache.getEntity(cls, args[0]);
		} else if (operateType.equals("getEntity") && args.length == 3) {
			cls = args[2].getClass();
			cacheObj = entityCache.getEntity(cls, args[0], args[1]);
		} else if (operateType.equals("getEntityList") && args.length == 3) {
			cls = args[2].getClass();
			cacheObj = entityCache.getEntityList(cls, args[0], args[1], null);
		} else if (operateType.equals("getAll")) {
			cls = args[0].getClass();
			cacheObj = entityCache.getEntityList(cls, "", new Object[] {}, null);
		}

		if (cls != null) {
			SerializableObject sobj = (SerializableObject) cls.newInstance();
			if (!sobj.needCached()) {
				return joinPoint.proceed();
			}
		}

		long begin1 = System.currentTimeMillis();

		if (cacheObj != null) {
			obj = cacheObj;
		} else {
			obj = joinPoint.proceed();
			if (operateType.equals("load") && args.length == 2) {
				entityCache.putEntity(args[1].getClass(), args[2], obj, false);
			} else if (operateType.equals("getEntity")) {
				entityCache.putEntity(args[2].getClass(), args[0], args[1], obj);
			} else if (operateType.equals("getEntityList") && args.length == 3) {
				entityCache.putEntityList(args[2].getClass(), args[0], args[1], (obj == null ? Collections.emptyList()
						: obj), null);
			} else if (operateType.equals("getAll")) {
				entityCache.putEntityList(args[0].getClass(), "", new Object[] {},
						(obj == null ? Collections.emptyList() : obj), null);
			}
		}

		// System.out.println(operateType + "," + args[0].getClass());
		if (operateType.equals("add")) {
			//entityCache.putEntity(args[0].getClass(), args[0], true);	// TODO
		} else if (operateType.equals("update")) {
			entityCache.updateEntity(args[0].getClass(), args[0]);
		} else if (operateType.equals("delete")) {
			entityCache.removeEntity(args[1].getClass(), args[0]);
		} else if (operateType.equals("execute") && args.length == 3) {
			entityCache.removeType(args[2].getClass());
		}
		if (LOGENABLE) {
			log.info("" + (System.currentTimeMillis() - begin) + ", " + (System.currentTimeMillis() - begin1) + ", "
					+ operateType);
		}
		return obj;
	}
}
